import Vue from "vue";
import axios from "axios";
import store from '../store/index';
import { extend } from '../utils/funs/copy';
import { isEmpty } from '../utils/funs/types';
import config from "../config";

/*
 * 加载中动画
 */
let counter = 0;
let loadingIns = null;
function showLoading() {
    if (counter == 0) {
        loadingIns = Vue.prototype.$toast.loading({
            duration: 0,
            loadingType: 'spinner',
        });
    }
    counter++;
}
function hideLoading() {
    counter--;
    if (counter == 0) {
        loadingIns.clear();
        loadingIns = null;
    }
}

let instance = axios.create();
/*
 * 请求拦截器
 */
instance.interceptors.request.use(config => {
    config.hasLoading && showLoading();
    return config;
}, err => {
    err.config.hasLoading && hideLoading();
    return Promise.reject(err);
});

/*
 * 响应拦截器
 * 后台接口返回的http状态码，只有两种：
 * 1）200(完成一次数据交互，无论成功或失败)，走响应成功拦截器
 * 2）401(令牌过期)，走响应错误拦截器
 * 那么如何区分一次http状态为200的数据交互的结果，是成功或失败？ res.data.meta.status
 * 1）200-300之间，代表交互成功，把数据交给外部调用者的then
 * 2）其他状态，代表交互失败，把失败信息reject给call方法内部的catch统一进行错误处理
 */
instance.interceptors.response.use(res => {
    res.config.hasLoading && hideLoading();
    let status = res.data.meta.status;
    if (status && status >= 200 && status < 300) {
        return res.data;
    } else {
        return Promise.reject(new Error(res.data.meta.msg));
    }
}, err => {
    err.config.hasLoading && hideLoading();
    let code = err.response && err.response.status;
    if (code == 401) {
        // 刷新token操作
        setTimeout(_ => {
            Vue.prototype.$toast.fail("会话异常，请重新登录！")
            store.commit("handleLogout");
        }, 1000);
    } else {
        return Promise.reject(err);
    }
});

export default function call(api, options) {
    if (!api) {
        throw new Error("未提供有效的api信息");
    }
    // 默认参数,api参数及用户参数合并
    let defaults = {
        baseURL: config._API_URL,
        url: '',
        method: 'get',
        data: null,
        params: null,
        timeout: '15000',
        headers: {},
        hasToken: true,
        hasLoading: false,
    }
    extend(defaults, api, options);
    // 给请求加上时间戳,防止缓存
    if (defaults.url.indexOf('?') > -1) {
        defaults.url += "&t=" + new Date().getTime();
    } else {
        defaults.url += "?t=" + new Date().getTime();
    }
    // 请求头携带token
    let _token = store.state.token;
    if (defaults.hasToken && !isEmpty(_token)) {
        defaults.headers.Authorization = _token.access_token;
    }
    // 发起请求
    // 1）全局捕获错误并统一处理（消息提示）
    // 2）把错误交给外部调用者的catch做个性处理
    return instance(defaults).catch(err => {
        Vue.prototype.$toast.fail(err.message || "错啦！");
        return Promise.reject(err);
    });
}